﻿using Devonline.AspNetCore;
using Devonline.Identity;
using Devonline.Identity.Admin;
using IdentityServer4.EntityFramework.Storage;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.OData;
using Microsoft.AspNetCore.OData.NewtonsoftJson;
using Microsoft.EntityFrameworkCore;
using OfficeOpenXml;
using Serilog;

ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
var builder = WebApplication.CreateBuilder(args);
var appSetting = builder.UseAppSetting<AdminSetting>();
if (appSetting == null)
{
    throw new Exception("缺少必要的基础配置项");
}

builder.Host.UseSerilog((context, logger) => logger.ReadFrom.Configuration(context.Configuration));

// Add services to the container.
var services = builder.Services;
services.AddLogging();
services.AddControllers()
    .AddOData(options => options.Count().Filter().Expand().Select().OrderBy().SetMaxTop(100)
    .AddRouteComponents("odata", Utility.BuildEdmModel()))
    .AddODataNewtonsoftJson()
    .AddJsonOptions();

#if DEBUG
services.AddControllersWithViews().AddRazorRuntimeCompilation();
#else
            services.AddControllersWithViews();
#endif

//TODO TBD 数据保护功能待验证
var dataProtection = appSetting.DataProtection;
services.AddSingleton(dataProtection);
services.AddDataProtection(x => x.ApplicationDiscriminator = dataProtection.ApplicationDiscriminator)
    .SetApplicationName(dataProtection.ApplicationName)
    .PersistKeysToStackExchangeRedis(StackExchange.Redis.ConnectionMultiplexer.Connect(dataProtection.Redis), dataProtection.KeyName);

var assemblyName = typeof(Program).Assembly.FullName;
services.AddDbContext<IdentityDbContext>(options => options.UseNpgsql(appSetting.IdentityDbContext, sql => sql.MigrationsAssembly(assemblyName)));
services.AddConfigurationDbContext(options => options.ConfigureDbContext = db => db.UseNpgsql(appSetting.IdentityDbContext, sql => sql.MigrationsAssembly(assemblyName)));
services.AddOperationalDbContext(options => options.ConfigureDbContext = db => db.UseNpgsql(appSetting.IdentityDbContext, sql => sql.MigrationsAssembly(assemblyName)));

services.AddIdentity<User, Role>()
    .AddEntityFrameworkStores<IdentityDbContext>()
    .AddPersonalDataProtection<AesProtector, DefaultKeyRing>()
    .AddDefaultTokenProviders();

services.AddIdentityServer(options =>
{
    options.Events.RaiseErrorEvents = true;
    options.Events.RaiseInformationEvents = true;
    options.Events.RaiseFailureEvents = true;
    options.Events.RaiseSuccessEvents = true;
    options.EmitStaticAudienceClaim = true;
    options.UserInteraction = appSetting.UserInteraction;
})
.AddAspNetIdentity<User>()
.AddConfigurationStore(options => options.ConfigureDbContext = db => db.UseNpgsql(appSetting.IdentityDbContext, sql => sql.MigrationsAssembly(assemblyName)))
.AddOperationalStore(options =>
{
    options.ConfigureDbContext = db => db.UseNpgsql(appSetting.IdentityDbContext, sql => sql.MigrationsAssembly(assemblyName));
    options.EnableTokenCleanup = true;
})
.AddDeveloperSigningCredential();

var auth = services.AddAuthentication();
if (appSetting.GitHub.Enable)
{
    auth.AddGitHub(options => appSetting.GitHub.Configure(options));
}

if (appSetting.Weixin.Enable)
{
    auth.AddWeixin(options => appSetting.Weixin.Configure(options));
}

if (appSetting.Alipay.Enable)
{
    auth.AddAlipay(options => appSetting.Alipay.Configure(options));
}

if (appSetting.QQ.Enable)
{
    auth.AddQQ(options => appSetting.QQ.Configure(options));
}

services.AddDataServices();

//TODO TBD
services.AddTransient<DbContext, IdentityDbContext>();
services.AddTransient<UserStore>();
services.AddTransient<RoleStore>();
services.AddTransient<ResourceAccessStore>();


var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
    app.UseHttpsRedirection();
}

app.UseRouting();
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.UseStaticFiles();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers().RequireAuthorization();
    endpoints.MapDefaultControllerRoute().RequireAuthorization();
    endpoints.MapControllerRoute(name: "api", pattern: "api/{controller=Home}/{action=Index}/{id?}");
});

app.Run();